1 module unit_threaded.randomized.random;
2 
3 /** This type will generate a $(D Gen!T) for all passed $(D T...).
4     Every call to $(D genValues) will call $(D gen) of all $(D Gen) structs
5     present in $(D values). The member $(D values) can be passed to every
6     function accepting $(D T...).
7 */
8 struct RndValueGen(T...) {
9     import std.meta : staticMap;
10     import std.random : Random;
11 
12     /* $(D Values) is a collection of $(D Gen) types created through
13        $(D ParameterToGen) of passed $(T ...).
14     */
15     static if (is(typeof(T[0]) == string[])) {
16         alias generators = T[1 .. $];
17         string[] parameterNames = T[0];
18     } else {
19         alias generators = T;
20         string[T.length] parameterNames;
21     }
22 
23     alias Values = staticMap!(ParameterToGen, generators);
24 
25     /// Ditto
26     Values values;
27 
28     /* The constructor accepting the required random number generator.
29        Params:
30        rnd = The required random number generator.
31     */
32     this(Random* rnd) @safe {
33         this.rnd = rnd;
34     }
35 
36     this(ref Random rnd) {
37         this.rnd = &rnd;
38     }
39 
40     /* The random number generator used to generate new value for all
41        $(D values).
42     */
43     Random* rnd;
44 
45     /** A call to this member function will call $(D gen) on all items in
46         $(D values) passing $(D the provided) random number generator
47     */
48     void genValues() {
49         assert(rnd !is null);
50         foreach (ref it; this.values) {
51             it.gen(*this.rnd);
52         }
53     }
54 
55     void toString(scope void delegate(const(char)[]) sink) {
56         import std.format : formattedWrite;
57 
58         foreach (idx, ref it; values) {
59             formattedWrite(sink, "'%s' = %s ", parameterNames[idx], it);
60         }
61     }
62 }
63 
64 /** A template that turns a $(D T) into a $(D Gen!T) unless $(D T) is
65     already a $(D Gen) or no $(D Gen) for given $(D T) is available.
66 */
67 template ParameterToGen(T) {
68     import unit_threaded.randomized.gen : isGen, Gen;
69 
70     static if (isGen!T)
71         alias ParameterToGen = T;
72     else static if (is(T : GenASCIIString!(S), S...))
73         alias ParameterToGen = T;
74     else {
75         static assert(__traits(compiles, Gen!T), "ParameterToGen does not handle " ~ T.stringof);
76         alias ParameterToGen = Gen!T;
77     }
78 }